package user_api

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"strconv"
	"study/server/global"
	"study/server/middleware"
	"study/server/model/request"
	resp "study/server/model/response"
	"study/server/model/system"
	"study/server/utils/captcha"
	"study/server/utils/email"
	"study/server/utils/my_bind"
	"study/server/utils/my_jwt"
	"study/server/utils/pwd"
)

type UserApi struct{}

func (u *UserApi) Login(c *gin.Context) {
	// 自定义绑定参数 -- 核心封装传统绑定函数,减少冗余代码
	/*
		errors.New("用户名为字符串,密码为数值类型,且不能为空") --> 返回给前端展示的错误信息
		内部核心err --> 存储于日志中
	*/
	req, err := my_bind.MyBind[request.LoginReq](errors.New("用户名为字符串,密码为数值类型,且不能为空"), c)
	if err != nil {
		return
	}

	// 校验验证码
	if global.Config.Captcha.Enable {
		// 校验验证码
		if req.CaptchaID == "" || req.CaptchaCode == "" {
			resp.FailWithMsg("验证码不能为空", c)
			return
		}
		// 校验验证码 -- 不管验证码是否正确,都不删除验证码
		if !captcha.Store.Verify(req.CaptchaID, req.CaptchaCode, false) {
			resp.FailWithMsg("验证码错误", c)
			return
		}
	}

	// 根据用户名查看存储的密码是否与输入的密码匹配
	var user system.UserModel
	err = global.DB.Where("user_name =?", req.Name).Preload("RoleList").First(&user).Error
	if err != nil {
		resp.FailWithMsg("用户名或密码错误", c)
		return
	}
	// 对查询到的密码解密
	if !pwd.LiftedHash(user.UserPassword, strconv.Itoa(req.Password)) {
		resp.FailWithMsg("用户名或密码错误", c)
		return
	}

	var roleList []uint
	for _, m := range user.RoleList {
		roleList = append(roleList, m.ID)
	}

	// 生成token
	token, _ := my_jwt.GenerateToken(my_jwt.CustomClaims{
		UserID:   user.ID,
		Username: user.UserName,
		RoleList: roleList,
	})
	respLogin := resp.LoginResp{
		Token: token,
		User: resp.CustomUser{
			NickName: user.NickName,
			Avatar:   user.Avatar,
			Email:    user.Email,
		},
	}

	resp.Ok("登陆成功", respLogin, c)
	return
}

func (u *UserApi) Register(c *gin.Context) {
	registerReq, err := my_bind.MyBind[request.RegisterReq](errors.New("请检查数据格式是否正确"), c)
	if err != nil {
		return
	}
	// 判断验证码
	if _, err := email.Verify(registerReq.EmailID, registerReq.Email, registerReq.EmailCode, true); err != nil {
		resp.FailWithMsg(err.Error(), c)
		return
	}
	// 校验密码
	if registerReq.Password != registerReq.RePassword {
		resp.FailWithMsg("两次密码不一致", c)
		return
	}
	// 判断邮箱是否被注册
	var user system.UserModel
	err = global.DB.Where("email =?", registerReq.Email).First(&user).Error
	if err == nil {
		resp.FailWithMsg("邮箱已被注册", c)
		return
	}

	// 创建用户
	hashPwd, err := pwd.GenerateHash(registerReq.Password)
	if err != nil {
		resp.FailWithMsg("密码加密失败", c)
		return
	}
	user = system.UserModel{
		UserName:     registerReq.Email,
		UserPassword: hashPwd,
		Email:        registerReq.Email,
	}
	err = global.DB.Create(&user).Error
	if err != nil {
		logrus.Error("注册失败", err)
		resp.FailWithMsg("注册失败", c)
		return
	}
	resp.OkWithMsg("注册成功,请返回登录页", c)
}

func (u *UserApi) UpdateUserInfo(c *gin.Context) {
	req, err := my_bind.MyBind[request.ModifyPwdReq](errors.New("请检查数据格式是否正确"), c)
	if err != nil {
		return
	}
	// 获取登录的用户信息
	claims := middleware.GetTokenFromContext(c)
	// 根据用户ID查询用户信息
	var user system.UserModel
	err = global.DB.Where("id =?", claims.UserID).First(&user).Error
	if err != nil {
		resp.FailWithMsg("用户不存在", c)
		return
	}
	if req.OldPassword == req.RePassword {
		resp.FailWithMsg("两次原密码不一致", c)
		return
	}
	// 校验旧密码 --> 需要更新旧密码时，旧密码不能为空，为空代表不更新密码
	if !pwd.LiftedHash(user.UserPassword, req.OldPassword) && req.NewPassword != "" {
		resp.FailWithMsg("旧密码错误", c)
		return
	}
	// 更新用户信息
	if req.NewPassword != "" {
		// 加密新密码
		hashPwd, err := pwd.GenerateHash(req.NewPassword)
		if err != nil {
			resp.FailWithMsg("密码加密失败", c)
			return
		}
		user.UserPassword = hashPwd
	}
	// 保存用户信息
	err = global.DB.Where("id =?", claims.UserID).Updates(&user).Error
	if err != nil {
		logrus.Error("更新失败", err)
		resp.FailWithMsg("更新失败", c)
		return
	}

	resp.OkWithMsg("密码更新成功", c)
}

func (u *UserApi) UpdateUserAvatar(c *gin.Context) {

}
